

package com.googlecode.flac4j.format.metadata;


import com.googlecode.jinahya.io.BitInput;
import com.googlecode.jinahya.io.BitOutput;

import java.io.IOException;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlType;


/**
 *
 * @author Jin Kwon <jinahya at gmail.com>
 */
@XmlType
public class Seektable extends AbstractData {


    /** GENERATED. */
    private static final long serialVersionUID = 4711222132762753389L;


    public Seektable() {
        super(BlockType.SEEKTABLE);
    }


    @Override
    public int getLengthInBytes() {
        return points.size() * Seekpoint.LENGTH_IN_BYTES;
    }


    @Override
    public void read(final BitInput input) throws IOException {

        points.clear();
        final int count =
            getHeader().getDataLength() / Seekpoint.LENGTH_IN_BYTES;
        for (int i = 0; i < count; i++) {
            final Seekpoint point = new Seekpoint();
            point.read(input);
            addPoint(point);
        }
    }


    @Override
    public void write(final BitOutput output) throws IOException {

        for (Seekpoint point : points) {
            point.write(output);
        }
    }


    /**
     * Clears points.
     */
    public void clearPoints() {
        points.clear();
    }


    /**
     * Returns point count.
     *
     * @return number of points added so far
     */
    public int getPointCount() {
        return points.size();
    }


    /**
     * Adds given <code>seekpoint</code>.
     *
     * @param point the seekpoint to add.
     */
    public void addPoint(final Seekpoint point) {

        if (point == null) {
            throw new NullPointerException("null seekpoint");
        }

        if (!point.isPlaceholder()) {
            for (Seekpoint listed : points) {
                if (listed.isPlaceholder()) {
                    continue;
                }
                if (listed.getSampleNumber() == point.getSampleNumber()) {
                    throw new IllegalArgumentException(
                        "duplicated piont by its sampleNumber: "
                        + point.getSampleNumber());
                }
            }
        }

        points.add(point);

        Collections.sort(points);
    }


    /**
     * Returns an unmodifiable list of <code>Seekpoint</code>s.
     *
     * @return an unmodifiable list of <code>Seekpoint</code>s.
     */
    public List<Seekpoint> getPoints() {
        return Collections.unmodifiableList(points);
    }


    @XmlElement(name = "point")
    @XmlElementWrapper(required = true)
    private final List<Seekpoint> points = new ArrayList<Seekpoint>();


}